package pl.prv.polanie.client.widgets.schedule;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import pl.prv.polanie.client.Planner;
import pl.prv.polanie.client.dto.CSCalendarDayDTO;
import pl.prv.polanie.client.dto.CSGroupDTO;
import pl.prv.polanie.client.dto.CSSubgroupDTO;
import pl.prv.polanie.client.dto.CSSubjectEventDTO;
import pl.prv.polanie.client.dto.CSVCalendarDayDTO;
import pl.prv.polanie.client.dto.DayDTO;
import pl.prv.polanie.client.model.Cache;
import pl.prv.polanie.client.model.CacheService;
import pl.prv.polanie.client.model.ViewDataProvider;
import pl.prv.polanie.client.widgets.schedule.widgets.DayHeader;
import pl.prv.polanie.client.widgets.schedule.widgets.DraggableZone;
import pl.prv.polanie.client.widgets.util.GUIUtil;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.MouseListenerAdapter;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

public class Day extends Composite {
	
	private static final String STYLE_DAY = "my-Day";
	private static final String STYLE_DAY_HEADER = "my-Day-header";
	private static final String STYLE_DAY_EVENTS = "my-Day-events";
	private static final String STYLE_DAY_EVENTS_SMALL = "my-Day-events-small";

	private VerticalPanel mainVP = new VerticalPanel();
	
	private DayHeader dayHeaderHTML = null;  
	private DraggableZone eventsDZ = new DraggableZone();
	
	private DayDTO dto = null;
	
//	private CalendarDayDTO calendarDayDTO = null;
	private CSCalendarDayDTO csCalendarDayDTO = null;
//	private CSVCalendarDayDTO csvCalendarDayDTO = null;
	
	List<LecturerPreferences> lecturerPreferences = new ArrayList<LecturerPreferences>();
	
	List<SubjectEventHint> subjectEventHints = new ArrayList<SubjectEventHint>();

	List<LocationForSubjectEvent> locationsForSubjectEvents = new ArrayList<LocationForSubjectEvent>();
	
	boolean fullTimeView;
	
	public Day(CSCalendarDayDTO dto, CSVCalendarDayDTO csvDto, boolean fullTimeView) {
		this.fullTimeView = fullTimeView;
		this.csCalendarDayDTO = dto;
		
		
		CSVCalendarDayDTO csvCD;
		if (csvDto != null) {
			csvCD = csvDto;
		} else {
			csvCD = ViewDataProvider.getCSVCalendarDay(dto);	
		}
		
		
//		this.csvCalendarDayDTO = csvCD;
		
				
		setupHeaderHTML(dto.getDayLabel(), "[" + dto.getId() + "]" + dto.getDayLabel());
		
		// + "," + csvCD.getDayLabel()
		setupEventsDZ();
		setupMainAP();
		
		initWidget(mainVP);
		setStyleName(STYLE_DAY);
	}
	
	
//	public Day(CalendarDayDTO dto) {
//		this.calendarDayDTO = dto;
//		
//		setupHeaderHTML(dto.getDayLabel());
//		setupEventsDZ();
//		setupMainAP();
//		
//		initWidget(mainVP);
//		setStyleName(STYLE_DAY);
//	}

	/**
	 * Przeszukuje i zwraca pierwszy SubjectEvent o podanym id.
	 */
	public SubjectEvent getSubjectEventByID(long id) {
		for (int i = 0; i < eventsDZ.getWidgetCount(); i++) {
			Widget w = eventsDZ.getWidget(i);
			
			if (w instanceof SubjectEvent) {
				SubjectEvent se = (SubjectEvent) w;
				
				CSSubjectEventDTO csSE = se.getSubjectEventDTO();
				if (csSE.getId() == id) {
					return se;
				}
			}
		}
		
		return null;
	}
	

	/**
	 * Usuwa z widoku z danego dnia wszystkie kontrolki SubjectEvent.
	 */
	public void removeAllSubjectEvents() {
		for (int i = eventsDZ.getWidgetCount()-1; i >= 0; i--) {
			Widget w = eventsDZ.getWidget(i);
			
			if (w instanceof SubjectEvent) {
				SubjectEvent se = (SubjectEvent) w;
				se.removeFromParent();
			}
		}
	}

	private void setupHeaderHTML(String title, String title2) {
		dayHeaderHTML = new DayHeader("" + title + "");
		dayHeaderHTML.setStyleName(STYLE_DAY_HEADER);
//		GUIUtil.prepareToResize(dayHeaderHTML);
		
		dayHeaderHTML.setTitle(title2);
		
		
		int dayHeaderW = 202;
		if (!fullTimeView) {
			dayHeaderW = 72;
		}
		
		dayHeaderHTML.setWidth(dayHeaderW+"px");
		
		dayHeaderHTML.addMouseListener(new MouseListenerAdapter() {
//			@Override
			public void onMouseEnter(Widget sender) {
				super.onMouseEnter(sender);
//				Planner.log("Day.getAbsoluteTOP " + dayHeaderHTML.getAbsoluteTop());
//
//				Planner.log ("Day.getAbsoluteTop2 " + DOM.getAbsoluteTop(dayHeaderHTML.getElement()));
//				
//				Planner.log("Day. DOM.getElementPropertyInt(w.getElement(), 'scrollTop') " + DOM.getElementPropertyInt(dayHeaderHTML.getElement(), "scrollTop") );
//				Planner.log("Window.getScrollTop() " + Window.getScrollTop());
				
				
//				int y = DOM.eventGetClientY(e)
//				- DOM.getAbsoluteTop(w.getElement())
//				+ DOM.getElementPropertyInt(w.getElement(), "scrollTop")
//				+ Window.getScrollTop();

//				Planner.log("Day" +
//						" w dniu znajduje sie obiektow: " + eventsDZ.getWidgetCount());
//				for (int i = 0; i < eventsDZ.getWidgetCount(); i++) {
//					Planner.log("Day.listuje kontrolki " + i + ": " + eventsDZ.getWidget(i));
//				}
			}
		});
		
//		dayHeaderHTML.setHeight(20+"px");
//		GUIUtil.restoreAfterResize(dayHeaderHTML);
	}	
	
	private void setupEventsDZ() {
		if (fullTimeView) {
			eventsDZ.setStyleName(STYLE_DAY_EVENTS);
		} else {
			eventsDZ.setStyleName(STYLE_DAY_EVENTS_SMALL);
		}
		//GUIUtil.prepareToResize(eventsDZ);
		
		int w = 200;
		int h = 540;
		if (!fullTimeView) {
			w = 70;
			h = 269;
		}
		
		eventsDZ.setWidth(w+"px");
		eventsDZ.setHeight(h+"px");
		//GUIUtil.restoreAfterResize(eventsDZ);
	}
	
	private void setupMainAP() {
		int w = 201;
		int h = 550;
		
		if (!fullTimeView) {
			w = 70;
			h = 269;
		}
		
		
		GUIUtil.prepareToResize(mainVP);
		mainVP.setWidth(w + "px");
		mainVP.setHeight(h + "px");
		GUIUtil.restoreAfterResize(mainVP);
		
//		mainAP.add(dayHeaderHTML, 0, 0);
//		mainAP.add(eventsDZ, 0, 20);
		mainVP.add(dayHeaderHTML);
		mainVP.add(eventsDZ);
		
		DOM.setStyleAttribute(DOM.getParent(dayHeaderHTML.getElement()), "border", "0px");
		
		mainVP.setCellHeight(dayHeaderHTML, 20+"px");
	}

	public DraggableZone getEventsDZ() {
		return eventsDZ;
	}

	public DayDTO getDto() {
		return dto;
	}
	
	public void addEvent(SubjectEvent e, boolean fullTimeSchedule) {
		int y = ScheduleUtil.convertFromStartTimeToPixels(e.getSubjectEventDTO().getStartTime().intValue(), CacheService.isFullTimeSemesterSelected());
		eventsDZ.add(e, 0, y);
	}
	
	public void setSubjectEventPosition(SubjectEvent e, int left) {
//		Planner.log("Day.setSubjectEventPosition: " + "ustawiam na pozycji " + left);
		if (e.getParent() == eventsDZ) {
			int top = eventsDZ.getWidgetTop(e);
			eventsDZ.setWidgetPosition(e, left, top);
		}
	}

	public void removeSubjectEventByID(long id) {
		SubjectEvent se = getSubjectEventByID(id);
		if (se != null) {
			eventsDZ.remove(se);
//			Planner.log("Day.removeSubjectEventByID() usunalem SE, id = " + id); 
		}
	}

	public void addSubjectEventHint(SubjectEventHint seh) {
		eventsDZ.add(seh, 0, seh.getY());
		subjectEventHints.add(seh);
	}
	
	public void addSubjectEventHint(SubjectEventHint seh, int left, int top, int width, int height) {
		eventsDZ.add(seh, left, top);
		seh.setWidth(width+"px");
		seh.setHeight(height+"px");
		subjectEventHints.add(seh);
	}

	
	public void addLecturerPreferences(LecturerPreferences lp) {
		eventsDZ.add(lp, 0, lp.getY());
		lecturerPreferences.add(lp);
	}
	
	public void addLocationForSubjectEvent(LocationForSubjectEvent lfse) {
		eventsDZ.add(lfse, 0, lfse.getY());
		locationsForSubjectEvents.add(lfse);
	}
	
	
	public void setParentSchedule(Schedule schedule) {
		eventsDZ.setParentSchedule(schedule);
	}
	
	protected void onAttach() {
		super.onAttach();
		
//		dayHeaderHTML.setWidth(200+"px");
//		dayHeaderHTML.setOffsetHeight(20);
//		
//		eventsDZ.setOffsetWidth(200);
//		eventsDZ.setOffsetHeight(540);

//		dayHeaderHTML.setOffsetWidth(200);
//		dayHeaderHTML.setOffsetHeight(20);
//		
//		eventsDZ.setOffsetWidth(200);
//		eventsDZ.setOffsetHeight(540);
	}

	/**
	 * Idzie w gore drzewa DOM i zwraca obiekt Schedule, jesli istnieje. Jesli nie, zwraca null.
	 * @return
	 */
	public Schedule getParentSchedule() {
		Widget w = getParent();
		
		while (w != null) {
			if (w instanceof Schedule) {
				return (Schedule)w;
			}
			w = w.getParent();
		}
		
		return null;
	}


	public CSCalendarDayDTO getCalendarDayDTO() {
		return csCalendarDayDTO;
	}


	public void setCalendarDayDTO(CSCalendarDayDTO csCalendarDayDTO) {
		this.csCalendarDayDTO = csCalendarDayDTO;
	}
	
	private List<SubjectEvent> getAllSubjectEventsInDay() {
		List<SubjectEvent> subjectEventsList = new ArrayList<SubjectEvent>();
		
		for (int i = 0; i < eventsDZ.getWidgetCount(); i++) {
			Widget w = eventsDZ.getWidget(i);
			
			if (w instanceof SubjectEvent) {
				SubjectEvent se = (SubjectEvent) w;
				subjectEventsList.add(se);
			}
		}
		
		return subjectEventsList;
	}
	
	
	/**
	 * Na podstawie istniejących 
	 */
	public void fixSubjectEventsPositions() {
		/**
		 * posegregowac po czasie rozpoczynania sie
		ustawiam pierwszy na podziale
		
		jesli jest parzysty/nieparzysty, to sprawdzam z poprzednim eventem i jesli sie uzupelniaja, to ustawiam w tym samym miejscu
		[TODO pozniej] trzeba  tez sprawdzic czy 2 wstecz nie jest tez takim uzupelniajacym

		jesli nie, to ssprawdzamy z wszystkimi poprzednimi z grupy i jesli polozenie x=0 nie koliduje z ktoryms z nich
		(czyli sie po prostu zmiesci) to dodaje tego eventa 
		to dodaje to polozenie na prawo od poprzednio dodanego eventa
		 */
		Planner.log("Day.fixSubjectEventsPositions: " + "BEGIN");
		long start = new Date().getTime();
		
		restoreSubjectEventsPrimalWidhts();
		
		List<SubjectEvent> subjectEventsList = getAllSubjectEventsInDay();
		
		if (subjectEventsList.size() == 0) {
			return;
		}

		Collections.sort(subjectEventsList);
		
		//WYPISANIE WSZYSTKOICH CSSUBJECTEVENT
//		Planner.log("Day.fixSubjectEventsPositions: " + "NA POCZATKU ------------------------");
		for (int i = 0; i < subjectEventsList.size(); i++) {
			CSSubjectEventDTO cs = ((SubjectEvent)subjectEventsList.get(i)).getSubjectEventDTO();
//			Planner.log("Day.fixSubjectEventsPositions: " + "i = " + i + ", " + cs);
		}
		
		

		
		
		for (int i = 0; i < subjectEventsList.size(); i++) {
			subjectEventsList.get(i).setLeftInDraggableZone(0);
//			subjectEventsList.get(i).setLeftInDraggableZone(0);
			
		}
		
		
		
		for (int i = 0; i < subjectEventsList.size(); i++) {
			
			SubjectEvent subjectEvent = (SubjectEvent)subjectEventsList.get(i);
			subjectEvent.setLeftInDraggableZone(0);
//			CSSubjectEventDTO cs = (subjectEvent).getSubjectEventDTO();
			
			//wyznaczyc indeks ostatniego eventu z grupy polaczonych eventow
			int lastElementInGroupIndex = i;
			for (int j = i+1; j < subjectEventsList.size(); j++) {
				
				SubjectEvent prevSE = (SubjectEvent)subjectEventsList.get(j-1);
				SubjectEvent se = (SubjectEvent)subjectEventsList.get(j);
				
				
				if (crossed(prevSE, se)) {
					lastElementInGroupIndex = j;
				} else {
					break;
				}
			}
			
			
			
			//jesli grupa kilkuelementowa, to je poukladac 1. cale elementy 2. parzysty 3. nieparzysty  komplementarnie parami
			if (lastElementInGroupIndex != i) {
				
//				Planner.log("Day.fixSubjectEventsPositions: " + "pierwsza grupa " + i + " -> " + lastElementInGroupIndex);
				
				List<SubjectEvent> wholeSEs = new ArrayList<SubjectEvent>();
				List<SubjectEvent> evenSEs = new ArrayList<SubjectEvent>();
				List<SubjectEvent> oddSEs = new ArrayList<SubjectEvent>();
				
				
				
				for (int j = i; j < lastElementInGroupIndex + 1; j++) {
					SubjectEvent se = subjectEventsList.get(j);
					
					int eventSort = se.getSubjectEventDTO().getEventSort();
					
					if (eventSort == 0) {
						wholeSEs.add(se);
					} else if (eventSort == 1) {
						evenSEs.add(se);
					} else if (eventSort == 2) {
						oddSEs.add(se);
					}
				}
				
				
				int numberOfElementsInGroup = lastElementInGroupIndex - i + 1;
				
						
				//usuwamy elementy z listy
				Planner.log("Day.fixSubjectEventsPositions: " + "usuwamy elementy z listy w liczbie " + numberOfElementsInGroup);
				
				for (int k = 0; k < numberOfElementsInGroup; k++) {
					subjectEventsList.remove(i);
				}
				
				
				
				Planner.log("Day.fixSubjectEventsPositions: whole " + wholeSEs.size() + ", even " + evenSEs.size() + ", odd " + oddSEs.size());
				for (int k = 0; k < wholeSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam z powrotem I pod indeks " + (i + k) + ", id " +
//							((SubjectEvent)wholeSEs.get(k)).getSubjectEventDTO().getId());
					subjectEventsList.add(i + k, wholeSEs.get(k));
				}
					
				int complementaryElements = Math.min(evenSEs.size(), oddSEs.size());
					
				for (int k = 0; k < complementaryElements; k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam II pod indeks " + (i + 2*k));
					subjectEventsList.add(i + 2*k, evenSEs.get(k));
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam III pod indeks " + (i + 2*k + 1));
					subjectEventsList.add(i + 2*k + 1, oddSEs.get(k));
				}
				
				for (int k = 0; k < complementaryElements; k++) {
					evenSEs.remove(0);
					oddSEs.remove(0);
				}
				
				for (int k = 0; k < evenSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam IV pod indeks " + (i + wholeSEs.size() + 2*complementaryElements + k));
					subjectEventsList.add(i + wholeSEs.size() + 2*complementaryElements + k, evenSEs.get(k));
				}
				
				for (int k = 0; k < oddSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam V pod indeks " + (i + wholeSEs.size() + 2*complementaryElements + k + evenSEs.size()));
					subjectEventsList.add(i + wholeSEs.size() + 2*complementaryElements + k + evenSEs.size(), oddSEs.get(k));
				}

				i = lastElementInGroupIndex + 1;
			}
		}
		
//		Collections.sort(subjectEventsList);
		
		//restorePrimalSubjectEventsWidhts();
		
		
		
		
		//ustawiamy pierwszy na podziale
		SubjectEvent firstSE = (SubjectEvent)subjectEventsList.get(0);
		addEvent(firstSE, CacheService.isFullTimeSemesterSelected());
		
		
		for (int j = 1; j < subjectEventsList.size(); j++) {
			SubjectEvent prevSE = (SubjectEvent)subjectEventsList.get(j-1);
			SubjectEvent se = (SubjectEvent)subjectEventsList.get(j);
			
//			long csPrevSEID = prevSE.getSubjectEventDTO().getId();
//			long csSEID = se.getSubjectEventDTO().getId();
			
			
			if (crossed(prevSE, se)) {
				
				int left = 0;
				
				if (complementary(prevSE, se)) {
					left = prevSE.getLeftInDraggableZone();
					int width = Math.min(prevSE.getOffsetWidth(), se.getOffsetWidth());
					
					prevSE.setWidth(width + "px");
					se.setWidth(width + "px");
				} else {
					left = prevSE.getLeftInDraggableZone() + prevSE.getWidth();
				}
				
//				Planner.log("Day.fixSubjectEventsPositions: " + "scrossowane " + csPrevSEID + ", " + csSEID );
//				Planner.log("Day.fixSubjectEventsPositions: " + "prevSE LEFT " + prevSE.getLeftInDraggableZone() + ", width " + prevSE.getWidth());
				se.setLeftInDraggableZone(left);
			} else {
//				Planner.log("Day.fixSubjectEventsPositions: " + "NIE scrossowane " + csPrevSEID + ", " + csSEID );
			}
		}
		
		Planner.log("Day.fixSubjectEventsPositions: " + (new Date().getTime() - start));
	}
	
	
	
	
	
	
	
	/**
	 * Na podstawie istniejących 
	 */
	public void fixSubjectEventsPositionsSTARA() {
		/**
		 * posegregowac po czasie rozpoczynania sie
		ustawiam pierwszy na podziale
		
		jesli jest parzysty/nieparzysty, to sprawdzam z poprzednim eventem i jesli sie uzupelniaja, to ustawiam w tym samym miejscu
		[TODO pozniej] trzeba  tez sprawdzic czy 2 wstecz nie jest tez takim uzupelniajacym

		jesli nie, to ssprawdzamy z wszystkimi poprzednimi z grupy i jesli polozenie x=0 nie koliduje z ktoryms z nich
		(czyli sie po prostu zmiesci) to dodaje tego eventa 
		to dodaje to polozenie na prawo od poprzednio dodanego eventa
		 */
		Planner.log("Day.fixSubjectEventsPositions: " + "BEGIN");
		
		List<SubjectEvent> subjectEventsList = new ArrayList<SubjectEvent>();
		
		for (int i = 0; i < eventsDZ.getWidgetCount(); i++) {
			Widget w = eventsDZ.getWidget(i);
			
			if (w instanceof SubjectEvent) {
				SubjectEvent se = (SubjectEvent) w;
				subjectEventsList.add(se);
			}
		}
		
		if (subjectEventsList.size() == 0) {
			return;
		}
		
		
		Collections.sort(subjectEventsList);
		
		//WYPISANIE WSZYSTKOICH CSSUBJECTEVENT
//		Planner.log("Day.fixSubjectEventsPositions: " + "NA POCZATKU ------------------------");
		for (int i = 0; i < subjectEventsList.size(); i++) {
			CSSubjectEventDTO cs = ((SubjectEvent)subjectEventsList.get(i)).getSubjectEventDTO();
//			Planner.log("Day.fixSubjectEventsPositions: " + "i = " + i + ", " + cs);
		}
		
		

		
		
		
		
		
		
		for (int i = 0; i < subjectEventsList.size(); i++) {
			
			SubjectEvent subjectEvent = (SubjectEvent)subjectEventsList.get(i);
			subjectEvent.setLeftInDraggableZone(0);
//			CSSubjectEventDTO cs = (subjectEvent).getSubjectEventDTO();
			
			//wyznaczyc indeks ostatniego eventu z grupy polaczonych eventow
			int lastElementInGroupIndex = i;
			for (int j = i+1; j < subjectEventsList.size(); j++) {
				
				SubjectEvent prevSE = (SubjectEvent)subjectEventsList.get(j-1);
				SubjectEvent se = (SubjectEvent)subjectEventsList.get(j);
				
				
				if (crossed(prevSE, se)) {
					lastElementInGroupIndex = j;
				} else {
					break;
				}
			}
			
			
			
			//jesli grupa kilkuelementowa, to je poukladac 1. cale elementy 2. parzysty 3. nieparzysty  komplementarnie parami
			if (lastElementInGroupIndex != i) {
				
//				Planner.log("Day.fixSubjectEventsPositions: " + "pierwsza grupa " + i + " -> " + lastElementInGroupIndex);
				
				List<SubjectEvent> wholeSEs = new ArrayList<SubjectEvent>();
				List<SubjectEvent> evenSEs = new ArrayList<SubjectEvent>();
				List<SubjectEvent> oddSEs = new ArrayList<SubjectEvent>();
				
				
				
				for (int j = i; j < lastElementInGroupIndex + 1; j++) {
					SubjectEvent se = subjectEventsList.get(j);
					
					int eventSort = se.getSubjectEventDTO().getEventSort();
					
					if (eventSort == 0) {
						wholeSEs.add(se);
					} else if (eventSort == 1) {
						evenSEs.add(se);
					} else if (eventSort == 2) {
						oddSEs.add(se);
					}
				}
				
				int numberOfElementsInGroup = lastElementInGroupIndex - i + 1;
				
						
				//usuwamy elementy z listy
//				Planner.log("Day.fixSubjectEventsPositions: " + "usuwamy elementy z listy w liczbie " + numberOfElementsInGroup);
				
				for (int k = 0; k < numberOfElementsInGroup; k++) {
					subjectEventsList.remove(i);
				}
				
				
				
//				Planner.log("Day.fixSubjectEventsPositions: whole " + wholeSEs.size() + ", even " + evenSEs.size() + ", odd " + oddSEs.size());
				for (int k = 0; k < wholeSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam z powrotem I pod indeks " + (i + k) + ", id " +
//							((SubjectEvent)wholeSEs.get(k)).getSubjectEventDTO().getId());
					subjectEventsList.add(i + k, wholeSEs.get(k));
				}
					
				int complementaryElements = Math.min(evenSEs.size(), oddSEs.size());
					
				for (int k = 0; k < complementaryElements; k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam II pod indeks " + (i + 2*k));
					subjectEventsList.add(i + 2*k, evenSEs.get(k));
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam III pod indeks " + (i + 2*k + 1));
					subjectEventsList.add(i + 2*k + 1, oddSEs.get(k));
				}
				
				for (int k = 0; k < complementaryElements; k++) {
					evenSEs.remove(0);
					oddSEs.remove(0);
				}
				
				for (int k = 0; k < evenSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam IV pod indeks " + (i + wholeSEs.size() + 2*complementaryElements + k));
					subjectEventsList.add(i + wholeSEs.size() + 2*complementaryElements + k, evenSEs.get(k));
				}
				
				for (int k = 0; k < oddSEs.size(); k++) {
//					Planner.log("Day.fixSubjectEventsPositions: " + "wstawiam V pod indeks " + (i + wholeSEs.size() + 2*complementaryElements + k + evenSEs.size()));
					subjectEventsList.add(i + wholeSEs.size() + 2*complementaryElements + k + evenSEs.size(), oddSEs.get(k));
				}

				i = lastElementInGroupIndex + 1;
			}
		}
		
		Collections.sort(subjectEventsList);
		
		//restorePrimalSubjectEventsWidhts();
		
		
		
		
		//ustawiamy pierwszy na podziale
		SubjectEvent firstSE = (SubjectEvent)subjectEventsList.get(0);
		addEvent(firstSE, CacheService.isFullTimeSemesterSelected());
		
		
		for (int j = 1; j < subjectEventsList.size(); j++) {
			SubjectEvent prevSE = (SubjectEvent)subjectEventsList.get(j-1);
			SubjectEvent se = (SubjectEvent)subjectEventsList.get(j);
			
//			long csPrevSEID = prevSE.getSubjectEventDTO().getId();
//			long csSEID = se.getSubjectEventDTO().getId();
			
			
			if (crossed(prevSE, se)) {
//				Planner.log("Day.fixSubjectEventsPositions: " + "scrossowane " + csPrevSEID + ", " + csSEID );
//				Planner.log("Day.fixSubjectEventsPositions: " + "prevSE LEFT " + prevSE.getLeftInDraggableZone() + ", width " + prevSE.getWidth());
				int left = prevSE.getLeftInDraggableZone() + prevSE.getWidth();
				se.setLeftInDraggableZone(left);
			} else {
//				Planner.log("Day.fixSubjectEventsPositions: " + "NIE scrossowane " + csPrevSEID + ", " + csSEID );
			}
		}
		
		
//		for (int i = 1; i < subjectEventsList.size(); i++) {
//			se = (SubjectEvent)subjectEventsList.get(i);
//			
//			//	jesli jest parzysty/nieparzysty, to sprawdzam z poprzednim eventem
//			//i jesli sie uzupelniaja, to ustawiam w tym samym miejscu
//			boolean oddOrEven = se.getSubjectEventDTO().getEventSort() > 0;
//			SubjectEvent prevSE = (SubjectEvent)subjectEventsList.get(i-1);
//			if (oddOrEven && complementary(se, prevSE)) {
//					int prevLeft = ((DraggableZone)prevSE.getParent()).getWidgetLeft(prevSE);
//					Planner.log("Day.fixSubjectEventsPositions: " + " JEDYNKA");
//					setSubjectEventPosition(se, prevLeft);
//					//addEvent(se);
//			} else {
//				//ustawaimy na lewo i sprawdzamy czy takie polozenie koliduje z ktoryms
//				//z poprzednich nalezacych do jednego bloku zazebiajacych sie eventow 
//				
//				
//				//zwrocic index polozonego najblizej poczatku listy subjectEventa,
//				//ktory zahacza z podanym 
//				
//				//wyznaczyc ixowa wpsolrzedna pierwszego eventa nalezacego do bloku
//				
//				int left = 0;
//				
//				
//				if (crossed(se, prevSE)) {
//					left = prevSE.getLeftInDraggableZone() + prevSE.getOffsetWidth();
//				}
//				
//				
//				Planner.log("Day.fixSubjectEventsPositions: " + " DWOJKA");
//				setSubjectEventPosition(se, left);
//				
//				
//				//TODO
////				setSubjectEventPosition(se, 0);
////				int topIndexOfCrossedSubjectEvents = getTopIndexOfCrossedSubjectEvents(subjectEventsList, se);
////				
////				//jechac od polozonych najblizej poczatku listy
////				for (int j = 0; j < subjectEventsList.indexOf(se); j++) {
////				}
//				
//			}
//			
//		}
	}
	
	
	/**
	 * Pobiera posortowana liste SE i sprawdza wszystkie wczesniejsze subjecteventy od podanego sei wyznacza gorna granice bloku.
	 * zwraca index najblizszego, najwyzej polozonego SE, ktory jest zakleszczony z podanym  
	 * @param subjectEventsList
	 * @return
	 */
	public int getTopIndexOfCrossedSubjectEvents(List<SubjectEvent> subjectEventsList, SubjectEvent se) {
		int index = subjectEventsList.indexOf(se);
		
		int topCrossedIndex = 0;
		
		if (index == 0) {
			topCrossedIndex = 0;
//			topCrossedIndex = se.getTopInDraggableZone();
			return topCrossedIndex;
		} else {
			//przegladamy polozone wyzej SE
			for (int i = index; i >= 0; i--) {
				SubjectEvent prevSE = subjectEventsList.get(i);
				SubjectEvent prevSE2 = subjectEventsList.get(i-1);
				
				if (crossed(prevSE, prevSE2)) {
					topCrossedIndex = i-1;
					//topCrossedIndex = prevSE2.getTopInDraggableZone();
				} else {
					break;
				}
			}
		}
		
		return topCrossedIndex;
	}
	
	
	
	/**
	 * Sprawdza czy dwa podane subjectEventy sie uzupelniaja (czyli odbywaja sie w tym samym czasie)
	 * @param se1
	 * @param se2
	 * @return
	 */
	private boolean complementary(SubjectEvent se1, SubjectEvent se2) {
		CSSubjectEventDTO csSE1 = se1.getSubjectEventDTO();
		CSSubjectEventDTO csSE2 = se2.getSubjectEventDTO();
		
		if (csSE1.getStartTime().intValue() == csSE2.getStartTime().intValue() &&
				csSE1.getDuration().intValue() == csSE2.getDuration().intValue()
		) {
			if (
					(csSE1.getEventSort() == 1 && csSE2.getEventSort() == 2) ||
					(csSE2.getEventSort() == 2 && csSE1.getEventSort() == 1)
				) {
				
				return true;
			}
		}
		return false;
	}
	
	
	/**
	 * Sprawdza czy dwa SubjectEventy sie ze soba zazebiaja.
	 * @param se1
	 * @param se2
	 * @return
	 */
	private boolean crossed(SubjectEvent se1, SubjectEvent se2) {
		CSSubjectEventDTO csSE1 = se1.getSubjectEventDTO();
		CSSubjectEventDTO csSE2 = se2.getSubjectEventDTO();
		
		if (csSE1.getStartTime().intValue() >= csSE2.getStartTime().intValue() && csSE1.getStartTime().intValue() < csSE2.getStartTime().intValue() + 
				csSE2.getDuration().intValue()) {
			return true;
		}
		
		if (csSE2.getStartTime().intValue() >= csSE1.getStartTime().intValue() && csSE2.getStartTime().intValue() < csSE1.getStartTime().intValue() +
				csSE1.getDuration().intValue()) {
			return true;
		}
		
		return false;
	}

	/**
	 * Ustawia szerokosci SEsow na podstawie liczebnosci grup i podgrup zajeciowych.
	 */
	private void restoreSubjectEventsPrimalWidhts() {
		
		List<SubjectEvent> subjectEventsList = getAllSubjectEventsInDay();
		
		for (int i = 1; i < subjectEventsList.size(); i++) {
			subjectEventsList.get(i).restorePrimalWidth();
		}
	}
	
	/**
	 * Zwraca odleglosc SE od lewej krawedzi DragggableZone.
	 */
	public int getSubjectEventWidgetLeft(SubjectEvent se) {
		return eventsDZ.getWidgetLeft(se);
	}
	
	/**
	 * Zwraca odleglosc SE od gornej krawedzi DragggableZone.
	 */
	public int getSubjectEventWidgetTop(SubjectEvent se) {
		return eventsDZ.getWidgetTop(se);
	}	
	
	
	
	
	
	
	
	
	
}
